import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.Instance;
import com.amazonaws.services.ec2.model.InstanceState;
import com.amazonaws.services.ec2.model.InstanceStateChange;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.ec2.model.TerminateInstancesResult;

/**
 * 
 */

/**
 * @author karthik
 *
 */
public class AmazonEC2Controller extends CloudController {
	static final String tagString="InterCloud";
    private AmazonEC2 ec2;
    private  List<Tag> tagList;
	AmazonEC2Controller(String AccessKey, String SecretKey) {
		//BasicAWSCredentials basiccred = new BasicAWSCredentials(AccessKey,SecretKey);
		BasicAWSCredentials basiccred = new BasicAWSCredentials("AKIAJ3P75SETUDVPGQRQ","wwhqRV5dIssyEMd4wy+0MxF5QP6r25z3JLnHyFfS");
        ec2 = new AmazonEC2Client(basiccred);
        tagList = new ArrayList<Tag>();
        Tag tag = new Tag(tagString,"");
    	tagList.add(tag);
    	microInstance = "m1.small";
    	smallInstance = "t1.micro";
    	largeInstance = "m1.large";
	}

	/* (non-Javadoc)
	 * @see CloudController#DeleteInstance(int)
	 */
	@Override
	boolean deleteInstance(String InstanceId) {
		return false;
	}

	/* (non-Javadoc)
	 * @see CloudController#GetInstanceInfo(int)
	 */
	@Override
	String getInstanceInfo(String InstanceId) {
		DescribeInstancesRequest request = new DescribeInstancesRequest();
    	DescribeInstancesResult result = new DescribeInstancesResult();
    	request.withInstanceIds(InstanceId);
    	try {
    		result = ec2.describeInstances(request);
    		List<Reservation> reservations = result.getReservations();
    		Set<Instance> instances = new HashSet<Instance>();
    		List<Instance> inst = new ArrayList<Instance>();
    		List<String> instshutdown = new ArrayList<String>();
    		for (Reservation reservation : reservations) {
    			instances.addAll(reservation.getInstances());
    			inst.addAll(reservation.getInstances());
    		}
    		Iterator<Instance> itr = inst.iterator();
    		while(itr.hasNext()) {
    			Instance instance = itr.next();
    			instshutdown.add(instance.getInstanceId());
    			System.out.print("Instance Information: ");
    			System.out.println(instance.getInstanceId());
    			System.out.println("Architecture: "+instance.getArchitecture());
    			System.out.println("OS: "+instance.getPlatform());
    			System.out.println("IP Address of the instance is: "+instance.getPublicIpAddress());
    			System.out.println("Virtualization type: "+instance.getVirtualizationType());
    			InstanceState state = instance.getState();
    			System.out.println("Current State of Instance: "+state.getName());
    			System.out.println("*********************************************");
    		}
    		
    		
    	}
    	catch(AmazonServiceException ase) {
    		System.out.println("Amazon Service Exception Caught: "+ase.getMessage());
    	}
    	catch(AmazonClientException ace) {
    		System.out.println("Amazon Client Exception Caught: "+ace.getMessage());
    	}
    	
    	return null;
	}

	/* (non-Javadoc)
	 * @see CloudController#GetRunningInstances()
	 */
	@Override
	String getRunningInstances() {
		try {
    		DescribeInstancesRequest request = new DescribeInstancesRequest();
    		Filter filter = new Filter();
    		filter.setName("tag-key");
    		filter.withValues(tagString);
    		request.withFilters(filter);
    		DescribeInstancesResult result = ec2.describeInstances(request);
    		List<Reservation> reservations = result.getReservations();
    		Set<Instance> instances = new HashSet<Instance>();
    		/*Get all the running instances and shutdown. 
    		 */
    		List<Instance> inst = new ArrayList<Instance>();
    		List<String> instshutdown = new ArrayList<String>();
    		for (Reservation reservation : reservations) {
    			instances.addAll(reservation.getInstances());
    			inst.addAll(reservation.getInstances());
    		}
    		Iterator<Instance> itr = inst.iterator();
    		while(itr.hasNext()) {
    			Instance instance = itr.next();
    			instshutdown.add(instance.getInstanceId());
    			System.out.print("Instance Information: ");
    			System.out.println(instance.getInstanceId());
    			InstanceState state = instance.getState();
    			System.out.println("Current State of Instance: "+state.getName());
    			System.out.println("*********************************************");
    		}
    	}
    	catch(AmazonServiceException ase) {
    		System.out.println("Amazon Service Exception Caught: "+ase.getMessage());
    	}
    	catch(AmazonClientException ace) {
    		System.out.println("Amazon Client Exception Caught: "+ace.getMessage());
    	}
		return null;
	}

	/* (non-Javadoc)
	 * @see CloudController#LaunchInstance(java.lang.String)
	 */
	@Override
	String launchInstance(String amiId,String InstanceType) {
		RunInstancesResult result = new RunInstancesResult();
    	RunInstancesRequest runInstancesRequest = new RunInstancesRequest(amiId,1,1);
    	runInstancesRequest.setInstanceType(InstanceType);
    	try{
    		result = ec2.runInstances(runInstancesRequest);
    		/*Every instance newly launched will be tagged with the tag InterCloud
    		 * in order to differentiate from the resources launched from this platform 
    		 * and general users of AWS.
    	 	*/
    		Reservation reservation = result.getReservation();
    		List<Instance> instances = reservation.getInstances();
    		List<String> instanceList = new ArrayList<String>();
    		Iterator<Instance> itr = instances.iterator();
    		while(itr.hasNext()) {
    			instanceList.add(itr.next().getInstanceId());
       		}
    		CreateTagsRequest tagsRequest = new CreateTagsRequest(instanceList,tagList);
    		ec2.createTags(tagsRequest);
    	}
    	catch(AmazonServiceException ase) {
    		System.out.println("Amazon Service Exception Caught: "+ase.getMessage());
    	}
    	catch(AmazonClientException ace) {
    		System.out.println("Amazon Client Exception Caught: "+ace.getMessage());
    	}
		return null;
	}

	/* (non-Javadoc)
	 * @see CloudController#ShutdownInstance(int)
	 */
	@Override
	boolean shutdownInstance(String InstanceId) {
		List<String> instances = new ArrayList<String>();
    	instances.add(InstanceId);
    	try {
    		TerminateInstancesRequest terminateInstancesRequest = new TerminateInstancesRequest(instances);
    		TerminateInstancesResult result = ec2.terminateInstances(terminateInstancesRequest);
    		List<InstanceStateChange> terminatingInstances = result.getTerminatingInstances();
        	Iterator<InstanceStateChange> itr = terminatingInstances.iterator();
        	while(itr.hasNext()) {
        		InstanceStateChange instanceStateChange = itr.next();
        		System.out.println(instanceStateChange.getCurrentState().toString());
        	}
        	return true;
    	}
    	catch(AmazonServiceException ase) {
    		System.out.println("Amazon Service Exception Caught: "+ase.getMessage());
    		return false;
    	}
    	catch(AmazonClientException ace) {
    		System.out.println("Amazon Client Exception Caught: "+ace.getMessage());
    		return false;
    	}
    	
		
	}

}
